package cn.org.atool.generator.util;

import cn.org.atool.fluent.mybatis.metadata.DbType;
import cn.org.atool.generator.annotation.Tables;

import javax.sql.DataSource;
import java.sql.Connection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

import static cn.org.atool.generator.util.GeneratorHelper.isBlank;

/**
 * 利用schemacrawler工具获取表元数据信息
 *
 * @author wudarui
 */
public class SchemaKits {
    public static final String SCHEMA_NOT_SPECIFIED = "NOT_SPECIFIED";
    private static final String SCHEMA_NOT_FOUND = "Unable to parse schemaName from URL, please specify it explicitly: @Tables(schema=\"yourSchema\")";

    public static TableKits tableKits(DbType dbType, Connection connection) {
        return new TableKits(dbType, connection);
    }

    public static String getSchemaName(Tables tables, DataSource dataSource) {
        String schemaName = getSchema(tables);
        if (!Objects.equals(SCHEMA_NOT_SPECIFIED, schemaName)) {
            return schemaName;
        }
        try {
            String schema = dataSource.getConnection().getSchema();
            if (isBlank(schema)) {
                schema = dataSource.getConnection().getCatalog();
            }
            if (!isBlank(schema)) {
                return schema;
            }
        } catch (Exception e) {
            throw new RuntimeException(SCHEMA_NOT_FOUND, e);
        }
        throw new RuntimeException(SCHEMA_NOT_FOUND);
    }

    public static String getSchemaName(Tables tables, String url) {
        String schemaName = getSchema(tables);
        if (!Objects.equals(SCHEMA_NOT_SPECIFIED, schemaName)) {
            return schemaName;
        } else if (isBlank(url)) {
            throw new RuntimeException(SCHEMA_NOT_FOUND);
        }
        String _url = url;
        int index = url.indexOf('?');
        if (index == -1) {
            index = url.indexOf(';');
        }
        if (index > 0) {
            _url = url.substring(0, index);
        }
        int first = _url.indexOf('/');
        int last = _url.lastIndexOf('/');
        if (last - first > 3 && (last + 1) < _url.length()) {//间隔4个字符以上, 避免 jdbc:// 子串
            return _url.substring(last + 1);
        }
        throw new RuntimeException(SCHEMA_NOT_FOUND);
    }

    static boolean isSchema(String fullName, String schemaName) {
        if (Objects.equals(fullName, schemaName) || fullName.matches(schemaName)) {
            return true;
        } else {
            int len = fullName.length();
            char first = fullName.charAt(0);
            char last = fullName.charAt(len - 1);
            return !isLetterOrDigit(first) && !isLetterOrDigit(last) &&
                Objects.equals(fullName.substring(1, len - 1), schemaName);
        }
    }

    /**
     * 字符是 字母/数字/下划线
     */
    static boolean isLetterOrDigit(char ch) {
        return Character.isLetterOrDigit(ch) || ch == '_';
    }

    public static String getSchema(Tables tables) {
        if (Objects.equals(tables.schema(), SCHEMA_NOT_SPECIFIED)) {
            String schema = tables.dbType().feature.getFixSchema();
            return schema == null ? tables.schema() : schema;
        } else {
            return tables.schema();
        }
    }

    public static final Set<String> NEED_LENGTH_TYPES = new HashSet<String>() {
        {
            this.add("VARCHAR");
            this.add("VARCHAR2");
        }
    };

    public static final Set<String> NEED_SCALE_TYPES = new HashSet<String>() {
        {
            this.add("NUMBER");
        }
    };
}